{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "pMiXbQ9xnIT4"
   },
   "source": [
    "# Curating a Dataset From the ChEMBL Database\n",
    "\n",
    "In this notebook, we'll download and format data from the [ChEMBL](https://www.ebi.ac.uk/chembl/) database for machine learning (ML) purposes. To begin, we need to identify the **ChEMBL ID** for our target of interest. This is often easiest to do by using the **UniProt ID**, which can typically be found from a [UniProt Website](https://www.uniprot.org/) or looking at a relevant protein structure in the PDB. For this notebook, we will download data for [Epidermal Growth Factor Receptor (EGFR)](https://www.uniprot.org/uniprotkb/P00533/entry), a protein that plays a significant role in cancer.\n",
    "\n",
    "Our task is made easier by the [chembl-downloader](https://github.com/cthoyt/chembl-downloader) package written Charles Tapley-Hoyt. This library simplifies the process of downloading and querying the ChEMBL database. For more on the chEMBL-downloader please see Charlie's [paper](https://joss.theoj.org/papers/10.21105/joss.08844) in The Journal of Open Source Software."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "31cj6RGonRzw"
   },
   "source": [
    "Install the necessary Python libraries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "2QAJuk1VJlSX",
    "outputId": "380c325a-7d6d-42f0-ed49-aba4bd4fbe40"
   },
   "outputs": [],
   "source": [
    "import sys\n",
    "IN_COLAB = 'google.colab' in sys.modules\n",
    "if IN_COLAB:\n",
    "  !uv pip install --system pandas chembl_downloader"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "IelA6-5unaYC"
   },
   "source": [
    "Import the libraries we will use\n",
    "- chembl_downloader - allows easy downloads and access to the ChEMBL database\n",
    "- pandas - enables access to data tables\n",
    "- sys - provides access to system functionality\n",
    "- files - allows downloads from Google Colab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "id": "vsSQilSQOfte"
   },
   "outputs": [],
   "source": [
    "import chembl_downloader\n",
    "import pandas as pd\n",
    "import sys\n",
    "IN_COLAB = 'google.colab' in sys.modules\n",
    "if IN_COLAB:\n",
    "  from google.colab import files"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "82dEAz5IzPZN"
   },
   "source": [
    "To begin, we will use the chembl-downloader to download a file containing the mapping of UniProt IDs to ChEMBL IDs. Once we've downloaded the file we can look up the ChEMBL ID corresponding to the UniProt ID for EGFR. If you want to look for a different protein, change the `uniprot_id` variable below. Make sure the query below returned 1 row and ChEMBL_ID has a value. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 81
    },
    "id": "aXsGJ2Z0S-W3",
    "outputId": "2ede39b8-057e-44b7-832d-126f9fb8d068"
   },
   "outputs": [
    {
     "ename": "ConnectionError",
     "evalue": "HTTPSConnectionPool(host='ftp.ebi.ac.uk', port=443): Max retries exceeded with url: /pub/databases/chembl/ChEMBLdb/latest/README (Caused by NameResolutionError(\"<urllib3.connection.HTTPSConnection object at 0x1170eb210>: Failed to resolve 'ftp.ebi.ac.uk' ([Errno 8] nodename nor servname provided, or not known)\"))",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mgaierror\u001b[39m                                  Traceback (most recent call last)",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/urllib3/connection.py:198\u001b[39m, in \u001b[36mHTTPConnection._new_conn\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m    197\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m198\u001b[39m     sock = \u001b[43mconnection\u001b[49m\u001b[43m.\u001b[49m\u001b[43mcreate_connection\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m    199\u001b[39m \u001b[43m        \u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_dns_host\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mport\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    200\u001b[39m \u001b[43m        \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    201\u001b[39m \u001b[43m        \u001b[49m\u001b[43msource_address\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43msource_address\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    202\u001b[39m \u001b[43m        \u001b[49m\u001b[43msocket_options\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43msocket_options\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    203\u001b[39m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    204\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m socket.gaierror \u001b[38;5;28;01mas\u001b[39;00m e:\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/urllib3/util/connection.py:60\u001b[39m, in \u001b[36mcreate_connection\u001b[39m\u001b[34m(address, timeout, source_address, socket_options)\u001b[39m\n\u001b[32m     58\u001b[39m     \u001b[38;5;28;01mraise\u001b[39;00m LocationParseError(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mhost\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m, label empty or too long\u001b[39m\u001b[33m\"\u001b[39m) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m60\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m res \u001b[38;5;129;01min\u001b[39;00m \u001b[43msocket\u001b[49m\u001b[43m.\u001b[49m\u001b[43mgetaddrinfo\u001b[49m\u001b[43m(\u001b[49m\u001b[43mhost\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mport\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfamily\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msocket\u001b[49m\u001b[43m.\u001b[49m\u001b[43mSOCK_STREAM\u001b[49m\u001b[43m)\u001b[49m:\n\u001b[32m     61\u001b[39m     af, socktype, proto, canonname, sa = res\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/socket.py:974\u001b[39m, in \u001b[36mgetaddrinfo\u001b[39m\u001b[34m(host, port, family, type, proto, flags)\u001b[39m\n\u001b[32m    973\u001b[39m addrlist = []\n\u001b[32m--> \u001b[39m\u001b[32m974\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m res \u001b[38;5;129;01min\u001b[39;00m \u001b[43m_socket\u001b[49m\u001b[43m.\u001b[49m\u001b[43mgetaddrinfo\u001b[49m\u001b[43m(\u001b[49m\u001b[43mhost\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mport\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfamily\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mtype\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mproto\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mflags\u001b[49m\u001b[43m)\u001b[49m:\n\u001b[32m    975\u001b[39m     af, socktype, proto, canonname, sa = res\n",
      "\u001b[31mgaierror\u001b[39m: [Errno 8] nodename nor servname provided, or not known",
      "\nThe above exception was the direct cause of the following exception:\n",
      "\u001b[31mNameResolutionError\u001b[39m                       Traceback (most recent call last)",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/urllib3/connectionpool.py:787\u001b[39m, in \u001b[36mHTTPConnectionPool.urlopen\u001b[39m\u001b[34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)\u001b[39m\n\u001b[32m    786\u001b[39m \u001b[38;5;66;03m# Make the request on the HTTPConnection object\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m787\u001b[39m response = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_make_request\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m    788\u001b[39m \u001b[43m    \u001b[49m\u001b[43mconn\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    789\u001b[39m \u001b[43m    \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    790\u001b[39m \u001b[43m    \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    791\u001b[39m \u001b[43m    \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtimeout_obj\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    792\u001b[39m \u001b[43m    \u001b[49m\u001b[43mbody\u001b[49m\u001b[43m=\u001b[49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    793\u001b[39m \u001b[43m    \u001b[49m\u001b[43mheaders\u001b[49m\u001b[43m=\u001b[49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    794\u001b[39m \u001b[43m    \u001b[49m\u001b[43mchunked\u001b[49m\u001b[43m=\u001b[49m\u001b[43mchunked\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    795\u001b[39m \u001b[43m    \u001b[49m\u001b[43mretries\u001b[49m\u001b[43m=\u001b[49m\u001b[43mretries\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    796\u001b[39m \u001b[43m    \u001b[49m\u001b[43mresponse_conn\u001b[49m\u001b[43m=\u001b[49m\u001b[43mresponse_conn\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    797\u001b[39m \u001b[43m    \u001b[49m\u001b[43mpreload_content\u001b[49m\u001b[43m=\u001b[49m\u001b[43mpreload_content\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    798\u001b[39m \u001b[43m    \u001b[49m\u001b[43mdecode_content\u001b[49m\u001b[43m=\u001b[49m\u001b[43mdecode_content\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    799\u001b[39m \u001b[43m    \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mresponse_kw\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    800\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    802\u001b[39m \u001b[38;5;66;03m# Everything went great!\u001b[39;00m\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/urllib3/connectionpool.py:488\u001b[39m, in \u001b[36mHTTPConnectionPool._make_request\u001b[39m\u001b[34m(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)\u001b[39m\n\u001b[32m    487\u001b[39m         new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)\n\u001b[32m--> \u001b[39m\u001b[32m488\u001b[39m     \u001b[38;5;28;01mraise\u001b[39;00m new_e\n\u001b[32m    490\u001b[39m \u001b[38;5;66;03m# conn.request() calls http.client.*.request, not the method in\u001b[39;00m\n\u001b[32m    491\u001b[39m \u001b[38;5;66;03m# urllib3.request. It also calls makefile (recv) on the socket.\u001b[39;00m\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/urllib3/connectionpool.py:464\u001b[39m, in \u001b[36mHTTPConnectionPool._make_request\u001b[39m\u001b[34m(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)\u001b[39m\n\u001b[32m    463\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m464\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_validate_conn\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconn\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    465\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m (SocketTimeout, BaseSSLError) \u001b[38;5;28;01mas\u001b[39;00m e:\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/urllib3/connectionpool.py:1093\u001b[39m, in \u001b[36mHTTPSConnectionPool._validate_conn\u001b[39m\u001b[34m(self, conn)\u001b[39m\n\u001b[32m   1092\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m conn.is_closed:\n\u001b[32m-> \u001b[39m\u001b[32m1093\u001b[39m     \u001b[43mconn\u001b[49m\u001b[43m.\u001b[49m\u001b[43mconnect\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m   1095\u001b[39m \u001b[38;5;66;03m# TODO revise this, see https://github.com/urllib3/urllib3/issues/2791\u001b[39;00m\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/urllib3/connection.py:704\u001b[39m, in \u001b[36mHTTPSConnection.connect\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m    703\u001b[39m sock: socket.socket | ssl.SSLSocket\n\u001b[32m--> \u001b[39m\u001b[32m704\u001b[39m \u001b[38;5;28mself\u001b[39m.sock = sock = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_new_conn\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    705\u001b[39m server_hostname: \u001b[38;5;28mstr\u001b[39m = \u001b[38;5;28mself\u001b[39m.host\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/urllib3/connection.py:205\u001b[39m, in \u001b[36mHTTPConnection._new_conn\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m    204\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m socket.gaierror \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[32m--> \u001b[39m\u001b[32m205\u001b[39m     \u001b[38;5;28;01mraise\u001b[39;00m NameResolutionError(\u001b[38;5;28mself\u001b[39m.host, \u001b[38;5;28mself\u001b[39m, e) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01me\u001b[39;00m\n\u001b[32m    206\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m SocketTimeout \u001b[38;5;28;01mas\u001b[39;00m e:\n",
      "\u001b[31mNameResolutionError\u001b[39m: <urllib3.connection.HTTPSConnection object at 0x1170eb210>: Failed to resolve 'ftp.ebi.ac.uk' ([Errno 8] nodename nor servname provided, or not known)",
      "\nThe above exception was the direct cause of the following exception:\n",
      "\u001b[31mMaxRetryError\u001b[39m                             Traceback (most recent call last)",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/requests/adapters.py:667\u001b[39m, in \u001b[36mHTTPAdapter.send\u001b[39m\u001b[34m(self, request, stream, timeout, verify, cert, proxies)\u001b[39m\n\u001b[32m    666\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m667\u001b[39m     resp = \u001b[43mconn\u001b[49m\u001b[43m.\u001b[49m\u001b[43murlopen\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m    668\u001b[39m \u001b[43m        \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m=\u001b[49m\u001b[43mrequest\u001b[49m\u001b[43m.\u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    669\u001b[39m \u001b[43m        \u001b[49m\u001b[43murl\u001b[49m\u001b[43m=\u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    670\u001b[39m \u001b[43m        \u001b[49m\u001b[43mbody\u001b[49m\u001b[43m=\u001b[49m\u001b[43mrequest\u001b[49m\u001b[43m.\u001b[49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    671\u001b[39m \u001b[43m        \u001b[49m\u001b[43mheaders\u001b[49m\u001b[43m=\u001b[49m\u001b[43mrequest\u001b[49m\u001b[43m.\u001b[49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    672\u001b[39m \u001b[43m        \u001b[49m\u001b[43mredirect\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m    673\u001b[39m \u001b[43m        \u001b[49m\u001b[43massert_same_host\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m    674\u001b[39m \u001b[43m        \u001b[49m\u001b[43mpreload_content\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m    675\u001b[39m \u001b[43m        \u001b[49m\u001b[43mdecode_content\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m    676\u001b[39m \u001b[43m        \u001b[49m\u001b[43mretries\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mmax_retries\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    677\u001b[39m \u001b[43m        \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    678\u001b[39m \u001b[43m        \u001b[49m\u001b[43mchunked\u001b[49m\u001b[43m=\u001b[49m\u001b[43mchunked\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m    679\u001b[39m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    681\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m (ProtocolError, \u001b[38;5;167;01mOSError\u001b[39;00m) \u001b[38;5;28;01mas\u001b[39;00m err:\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/urllib3/connectionpool.py:841\u001b[39m, in \u001b[36mHTTPConnectionPool.urlopen\u001b[39m\u001b[34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)\u001b[39m\n\u001b[32m    839\u001b[39m     new_e = ProtocolError(\u001b[33m\"\u001b[39m\u001b[33mConnection aborted.\u001b[39m\u001b[33m\"\u001b[39m, new_e)\n\u001b[32m--> \u001b[39m\u001b[32m841\u001b[39m retries = \u001b[43mretries\u001b[49m\u001b[43m.\u001b[49m\u001b[43mincrement\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m    842\u001b[39m \u001b[43m    \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merror\u001b[49m\u001b[43m=\u001b[49m\u001b[43mnew_e\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m_pool\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m_stacktrace\u001b[49m\u001b[43m=\u001b[49m\u001b[43msys\u001b[49m\u001b[43m.\u001b[49m\u001b[43mexc_info\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m[\u001b[49m\u001b[32;43m2\u001b[39;49m\u001b[43m]\u001b[49m\n\u001b[32m    843\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    844\u001b[39m retries.sleep()\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/urllib3/util/retry.py:519\u001b[39m, in \u001b[36mRetry.increment\u001b[39m\u001b[34m(self, method, url, response, error, _pool, _stacktrace)\u001b[39m\n\u001b[32m    518\u001b[39m     reason = error \u001b[38;5;129;01mor\u001b[39;00m ResponseError(cause)\n\u001b[32m--> \u001b[39m\u001b[32m519\u001b[39m     \u001b[38;5;28;01mraise\u001b[39;00m MaxRetryError(_pool, url, reason) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mreason\u001b[39;00m  \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n\u001b[32m    521\u001b[39m log.debug(\u001b[33m\"\u001b[39m\u001b[33mIncremented Retry for (url=\u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[33m'\u001b[39m\u001b[33m): \u001b[39m\u001b[38;5;132;01m%r\u001b[39;00m\u001b[33m\"\u001b[39m, url, new_retry)\n",
      "\u001b[31mMaxRetryError\u001b[39m: HTTPSConnectionPool(host='ftp.ebi.ac.uk', port=443): Max retries exceeded with url: /pub/databases/chembl/ChEMBLdb/latest/README (Caused by NameResolutionError(\"<urllib3.connection.HTTPSConnection object at 0x1170eb210>: Failed to resolve 'ftp.ebi.ac.uk' ([Errno 8] nodename nor servname provided, or not known)\"))",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001b[31mConnectionError\u001b[39m                           Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[5]\u001b[39m\u001b[32m, line 2\u001b[39m\n\u001b[32m      1\u001b[39m uniprot_id = \u001b[33m'\u001b[39m\u001b[33mQ9UNQ0\u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m2\u001b[39m uniprot_path = \u001b[43mchembl_downloader\u001b[49m\u001b[43m.\u001b[49m\u001b[43mdownload_uniprot_mapping\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m      3\u001b[39m uniprot_df = pd.read_csv(uniprot_path,sep=\u001b[33m\"\u001b[39m\u001b[38;5;130;01m\\t\u001b[39;00m\u001b[33m\"\u001b[39m,names=[\u001b[33m\"\u001b[39m\u001b[33mUniProt\u001b[39m\u001b[33m\"\u001b[39m, \u001b[33m\"\u001b[39m\u001b[33mChEMBL_ID\u001b[39m\u001b[33m\"\u001b[39m,\u001b[33m\"\u001b[39m\u001b[33mName\u001b[39m\u001b[33m\"\u001b[39m,\u001b[33m\"\u001b[39m\u001b[33mTarget_Type\u001b[39m\u001b[33m\"\u001b[39m],comment=\u001b[33m\"\u001b[39m\u001b[33m#\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m      4\u001b[39m result_df = uniprot_df.query(\u001b[33m\"\u001b[39m\u001b[33mUniProt == @uniprot_id and Target_Type == \u001b[39m\u001b[33m'\u001b[39m\u001b[33mSINGLE PROTEIN\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m)\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/chembl_downloader/api.py:1023\u001b[39m, in \u001b[36mdownload_uniprot_mapping\u001b[39m\u001b[34m(version, prefix, return_version)\u001b[39m\n\u001b[32m   1006\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mdownload_uniprot_mapping\u001b[39m(\n\u001b[32m   1007\u001b[39m     version: VersionHint | \u001b[38;5;28;01mNone\u001b[39;00m = \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[32m   1008\u001b[39m     *,\n\u001b[32m   1009\u001b[39m     prefix: Sequence[\u001b[38;5;28mstr\u001b[39m] | \u001b[38;5;28;01mNone\u001b[39;00m = \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[32m   1010\u001b[39m     return_version: \u001b[38;5;28mbool\u001b[39m = \u001b[38;5;28;01mFalse\u001b[39;00m,\n\u001b[32m   1011\u001b[39m ) -> Path | VersionPathPair:\n\u001b[32m   1012\u001b[39m \u001b[38;5;250m    \u001b[39m\u001b[33;03m\"\"\"Ensure the latest ChEMBL-UniProt target mapping TSV file.\u001b[39;00m\n\u001b[32m   1013\u001b[39m \n\u001b[32m   1014\u001b[39m \u001b[33;03m    :param version: The version number of ChEMBL to get. If none specified, uses\u001b[39;00m\n\u001b[32m   (...)\u001b[39m\u001b[32m   1021\u001b[39m \u001b[33;03m        file path to the downloaded ``*.txt`` file. Otherwise, just return the path.\u001b[39;00m\n\u001b[32m   1022\u001b[39m \u001b[33;03m    \"\"\"\u001b[39;00m\n\u001b[32m-> \u001b[39m\u001b[32m1023\u001b[39m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_download_helper\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m   1024\u001b[39m \u001b[43m        \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mchembl_uniprot_mapping.txt\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[32m   1025\u001b[39m \u001b[43m        \u001b[49m\u001b[43mversion\u001b[49m\u001b[43m=\u001b[49m\u001b[43mversion\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   1026\u001b[39m \u001b[43m        \u001b[49m\u001b[43mprefix\u001b[49m\u001b[43m=\u001b[49m\u001b[43mprefix\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   1027\u001b[39m \u001b[43m        \u001b[49m\u001b[43mreturn_version\u001b[49m\u001b[43m=\u001b[49m\u001b[43mreturn_version\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m   1028\u001b[39m \u001b[43m        \u001b[49m\u001b[43mfilename_repeats_version\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m   1029\u001b[39m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/chembl_downloader/api.py:184\u001b[39m, in \u001b[36m_download_helper\u001b[39m\u001b[34m(suffix, version, prefix, return_version, filename_repeats_version)\u001b[39m\n\u001b[32m    160\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m_download_helper\u001b[39m(\n\u001b[32m    161\u001b[39m     suffix: \u001b[38;5;28mstr\u001b[39m,\n\u001b[32m    162\u001b[39m     version: VersionHint | \u001b[38;5;28;01mNone\u001b[39;00m = \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[32m   (...)\u001b[39m\u001b[32m    166\u001b[39m     filename_repeats_version: \u001b[38;5;28mbool\u001b[39m = \u001b[38;5;28;01mTrue\u001b[39;00m,\n\u001b[32m    167\u001b[39m ) -> Path | VersionPathPair:\n\u001b[32m    168\u001b[39m \u001b[38;5;250m    \u001b[39m\u001b[33;03m\"\"\"Ensure the latest ChEMBL file with the given suffix is downloaded.\u001b[39;00m\n\u001b[32m    169\u001b[39m \n\u001b[32m    170\u001b[39m \u001b[33;03m    :param suffix: The suffix of the file\u001b[39;00m\n\u001b[32m   (...)\u001b[39m\u001b[32m    182\u001b[39m \u001b[33;03m    :raises ValueError: If file could not be downloaded\u001b[39;00m\n\u001b[32m    183\u001b[39m \u001b[33;03m    \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m184\u001b[39m     version_info = \u001b[43m_get_version_info\u001b[49m\u001b[43m(\u001b[49m\u001b[43mversion\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprefix\u001b[49m\u001b[43m=\u001b[49m\u001b[43mprefix\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    186\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m filename_repeats_version:\n\u001b[32m    187\u001b[39m         filename = \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mchembl_\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mversion_info.fmt_version\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;132;01m{\u001b[39;00msuffix\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/chembl_downloader/api.py:225\u001b[39m, in \u001b[36m_get_version_info\u001b[39m\u001b[34m(version, prefix)\u001b[39m\n\u001b[32m    222\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(version, VersionInfo):\n\u001b[32m    223\u001b[39m     \u001b[38;5;28;01mreturn\u001b[39;00m version\n\u001b[32m--> \u001b[39m\u001b[32m225\u001b[39m flavor = \u001b[43m_ensure_version_helper\u001b[49m\u001b[43m(\u001b[49m\u001b[43mversion\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    226\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m prefix \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m    227\u001b[39m     \u001b[38;5;66;03m# it's important that this is a None check so it's possible\u001b[39;00m\n\u001b[32m    228\u001b[39m     \u001b[38;5;66;03m# to pass an empty list\u001b[39;00m\n\u001b[32m    229\u001b[39m     prefix = PYSTOW_PARTS\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/chembl_downloader/api.py:243\u001b[39m, in \u001b[36m_ensure_version_helper\u001b[39m\u001b[34m(version)\u001b[39m\n\u001b[32m    241\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m_ensure_version_helper\u001b[39m(version: VersionHint | \u001b[38;5;28;01mNone\u001b[39;00m) -> _VersionFlavorsHelper:\n\u001b[32m    242\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m version \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m243\u001b[39m         version = \u001b[43mlatest\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    244\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(version, \u001b[38;5;28mint\u001b[39m):\n\u001b[32m    245\u001b[39m         \u001b[38;5;66;03m# versions 1-9 are left padded with a zero\u001b[39;00m\n\u001b[32m    246\u001b[39m         fmt_version = \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mversion\u001b[38;5;132;01m:\u001b[39;00m\u001b[33m02\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/chembl_downloader/api.py:116\u001b[39m, in \u001b[36mlatest\u001b[39m\u001b[34m(full, prefix)\u001b[39m\n\u001b[32m    109\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mlatest\u001b[39m(*, full: \u001b[38;5;28mbool\u001b[39m = \u001b[38;5;28;01mFalse\u001b[39;00m, prefix: Sequence[\u001b[38;5;28mstr\u001b[39m] | \u001b[38;5;28;01mNone\u001b[39;00m = \u001b[38;5;28;01mNone\u001b[39;00m) -> \u001b[38;5;28mstr\u001b[39m | VersionInfo:\n\u001b[32m    110\u001b[39m \u001b[38;5;250m    \u001b[39m\u001b[33;03m\"\"\"Get the latest version of ChEMBL as a string.\u001b[39;00m\n\u001b[32m    111\u001b[39m \n\u001b[32m    112\u001b[39m \u001b[33;03m    :returns: The latest version string of ChEMBL\u001b[39;00m\n\u001b[32m    113\u001b[39m \n\u001b[32m    114\u001b[39m \u001b[33;03m    :raises ValueError: If the latest README can not be parsed\u001b[39;00m\n\u001b[32m    115\u001b[39m \u001b[33;03m    \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m116\u001b[39m     res = \u001b[43mrequests\u001b[49m\u001b[43m.\u001b[49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[43mLATEST_README_URL\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m=\u001b[49m\u001b[32;43m5\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[32m    117\u001b[39m     res.raise_for_status()\n\u001b[32m    118\u001b[39m     \u001b[38;5;28;01mfor\u001b[39;00m line_binary \u001b[38;5;129;01min\u001b[39;00m res.iter_lines(decode_unicode=\u001b[38;5;28;01mTrue\u001b[39;00m):\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/requests/api.py:73\u001b[39m, in \u001b[36mget\u001b[39m\u001b[34m(url, params, **kwargs)\u001b[39m\n\u001b[32m     62\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mget\u001b[39m(url, params=\u001b[38;5;28;01mNone\u001b[39;00m, **kwargs):\n\u001b[32m     63\u001b[39m \u001b[38;5;250m    \u001b[39m\u001b[33mr\u001b[39m\u001b[33;03m\"\"\"Sends a GET request.\u001b[39;00m\n\u001b[32m     64\u001b[39m \n\u001b[32m     65\u001b[39m \u001b[33;03m    :param url: URL for the new :class:`Request` object.\u001b[39;00m\n\u001b[32m   (...)\u001b[39m\u001b[32m     70\u001b[39m \u001b[33;03m    :rtype: requests.Response\u001b[39;00m\n\u001b[32m     71\u001b[39m \u001b[33;03m    \"\"\"\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m73\u001b[39m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mget\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparams\u001b[49m\u001b[43m=\u001b[49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/requests/api.py:59\u001b[39m, in \u001b[36mrequest\u001b[39m\u001b[34m(method, url, **kwargs)\u001b[39m\n\u001b[32m     55\u001b[39m \u001b[38;5;66;03m# By using the 'with' statement we are sure the session is closed, thus we\u001b[39;00m\n\u001b[32m     56\u001b[39m \u001b[38;5;66;03m# avoid leaving sockets open which can trigger a ResourceWarning in some\u001b[39;00m\n\u001b[32m     57\u001b[39m \u001b[38;5;66;03m# cases, and look like a memory leak in others.\u001b[39;00m\n\u001b[32m     58\u001b[39m \u001b[38;5;28;01mwith\u001b[39;00m sessions.Session() \u001b[38;5;28;01mas\u001b[39;00m session:\n\u001b[32m---> \u001b[39m\u001b[32m59\u001b[39m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43msession\u001b[49m\u001b[43m.\u001b[49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m=\u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m=\u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/requests/sessions.py:589\u001b[39m, in \u001b[36mSession.request\u001b[39m\u001b[34m(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)\u001b[39m\n\u001b[32m    584\u001b[39m send_kwargs = {\n\u001b[32m    585\u001b[39m     \u001b[33m\"\u001b[39m\u001b[33mtimeout\u001b[39m\u001b[33m\"\u001b[39m: timeout,\n\u001b[32m    586\u001b[39m     \u001b[33m\"\u001b[39m\u001b[33mallow_redirects\u001b[39m\u001b[33m\"\u001b[39m: allow_redirects,\n\u001b[32m    587\u001b[39m }\n\u001b[32m    588\u001b[39m send_kwargs.update(settings)\n\u001b[32m--> \u001b[39m\u001b[32m589\u001b[39m resp = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mprep\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43msend_kwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    591\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m resp\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/requests/sessions.py:703\u001b[39m, in \u001b[36mSession.send\u001b[39m\u001b[34m(self, request, **kwargs)\u001b[39m\n\u001b[32m    700\u001b[39m start = preferred_clock()\n\u001b[32m    702\u001b[39m \u001b[38;5;66;03m# Send the request\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m703\u001b[39m r = \u001b[43madapter\u001b[49m\u001b[43m.\u001b[49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mrequest\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    705\u001b[39m \u001b[38;5;66;03m# Total elapsed time of the request (approximately)\u001b[39;00m\n\u001b[32m    706\u001b[39m elapsed = preferred_clock() - start\n",
      "\u001b[36mFile \u001b[39m\u001b[32m/opt/homebrew/Caskroom/miniforge/base/envs/rdkit_2025_03/lib/python3.11/site-packages/requests/adapters.py:700\u001b[39m, in \u001b[36mHTTPAdapter.send\u001b[39m\u001b[34m(self, request, stream, timeout, verify, cert, proxies)\u001b[39m\n\u001b[32m    696\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(e.reason, _SSLError):\n\u001b[32m    697\u001b[39m         \u001b[38;5;66;03m# This branch is for urllib3 v1.22 and later.\u001b[39;00m\n\u001b[32m    698\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m SSLError(e, request=request)\n\u001b[32m--> \u001b[39m\u001b[32m700\u001b[39m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mConnectionError\u001b[39;00m(e, request=request)\n\u001b[32m    702\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m ClosedPoolError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[32m    703\u001b[39m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mConnectionError\u001b[39;00m(e, request=request)\n",
      "\u001b[31mConnectionError\u001b[39m: HTTPSConnectionPool(host='ftp.ebi.ac.uk', port=443): Max retries exceeded with url: /pub/databases/chembl/ChEMBLdb/latest/README (Caused by NameResolutionError(\"<urllib3.connection.HTTPSConnection object at 0x1170eb210>: Failed to resolve 'ftp.ebi.ac.uk' ([Errno 8] nodename nor servname provided, or not known)\"))"
     ]
    }
   ],
   "source": [
    "uniprot_id = 'Q9UNQ0'\n",
    "uniprot_path = chembl_downloader.download_uniprot_mapping()\n",
    "uniprot_df = pd.read_csv(uniprot_path,sep=\"\\t\",names=[\"UniProt\", \"ChEMBL_ID\",\"Name\",\"Target_Type\"],comment=\"#\")\n",
    "result_df = uniprot_df.query(\"UniProt == @uniprot_id and Target_Type == 'SINGLE PROTEIN'\")\n",
    "chembl_id = None\n",
    "if len(result_df) > 0:\n",
    "    chembl_id = result_df.ChEMBL_ID.values[0]\n",
    "    print(f\"ChEMBL_ID = {chembl_id}\")\n",
    "else:\n",
    "    print(f\"No ChEMBL_ID found for {uniprot_id}\")\n",
    "print()\n",
    "result_df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "WSPkk1fRiRZp"
   },
   "source": [
    "To access the data corresponding to our target of interest, we need to use a relatively complex SQL query.  I borrowed thiis query from the [OpenADMET](https://github.com/OpenADMET/openadmet-toolkit/blob/main/openadmet/toolkit/database/chembl.py) data curation workflow. The function below encapsulates this query.  We provide the ChEMBL ID as input and the fuction returns the sql query.\n",
    "\n",
    "**One Important Note About This Query**     \n",
    "This query returns ChEMBL activity data as pChEMBL, which is the negative log of the molar activity (e.g. pIC50).  The pCHEMBL values are only returned where the **standard_relation** (>,<,=) is \"=\".  Consequently, this query won't return qualified values like **>30** or **<5**. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "id": "ZtX801b1J_kk"
   },
   "outputs": [],
   "source": [
    "def get_query(chembl_id):\n",
    "  query =f\"\"\"       -- Get all the activity data for a given target using its ChEMBL ID.\n",
    "        select\n",
    "            activities.assay_id                  as assay_id,\n",
    "            activities.doc_id                    as doc_id,\n",
    "            activities.standard_value            as standard_value,\n",
    "            molecule_hierarchy.parent_molregno   as molregno,\n",
    "            compound_structures.canonical_smiles as canonical_smiles,\n",
    "            compound_structures.standard_inchi_key as standard_inchi_key,\n",
    "            target_dictionary.tid                as tid,\n",
    "            target_dictionary.chembl_id          as target_chembl_id,\n",
    "            pchembl_value                        as pchembl_value,\n",
    "            molecule_dictionary.pref_name        as compound_name,\n",
    "            activities.standard_type             as standard_type,\n",
    "            activities.standard_value            as standard_value,\n",
    "            activities.standard_relation         as standard_relation,\n",
    "            activities.standard_units            as standard_units,\n",
    "            activities.bao_endpoint              as bao_endpoint,\n",
    "            assays.description                   as assay_description,\n",
    "            assays.assay_organism                as assay_organism,\n",
    "            assays.assay_strain                  as assay_strain,\n",
    "            assays.assay_tissue                  as assay_tissue,\n",
    "            assays.assay_type                    as assay_type,\n",
    "            assays.assay_cell_type               as assay_cell_type,\n",
    "            assays.assay_subcellular_fraction    as assay_subcellular_fraction,\n",
    "            assays.variant_id                    as variant_id,\n",
    "            docs.year                            as doc_year,\n",
    "            docs.journal                         as doc_journal,\n",
    "            docs.doi                             as doc_doi,\n",
    "            docs.title                           as doc_title,\n",
    "            docs.authors                         as doc_authors,\n",
    "            docs.abstract                        as doc_abstract,\n",
    "            docs.patent_id                       as doc_patent_id,\n",
    "            docs.pubmed_id                       as doc_pubmed_id,\n",
    "            docs.chembl_release_id               as doc_chembl_release_id\n",
    "        from activities\n",
    "        join assays ON activities.assay_id = assays.assay_id\n",
    "        join target_dictionary ON assays.tid = target_dictionary.tid\n",
    "        join target_components ON target_dictionary.tid = target_components.tid\n",
    "        join component_class ON target_components.component_id = component_class.component_id\n",
    "        join docs ON activities.doc_id = docs.doc_id\n",
    "        join molecule_dictionary ON activities.molregno = molecule_dictionary.molregno\n",
    "        join molecule_hierarchy ON molecule_dictionary.molregno = molecule_hierarchy.molregno\n",
    "        join compound_structures ON molecule_hierarchy.parent_molregno = compound_structures.molregno\n",
    "        where target_chembl_id = '{chembl_id}'\n",
    "        and activities.data_validity_comment IS null\n",
    "        and activities.standard_units = 'nM'\n",
    "        and pchembl_value is not null\"\"\"\n",
    "  return query"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "SFr-28urjXwt"
   },
   "source": [
    "Use the function above to get the SQL query."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "id": "ce5hltBLN-vv"
   },
   "outputs": [],
   "source": [
    "if chembl_id is not None:\n",
    "    sql = get_query(chembl_id)\n",
    "else:\n",
    "    print(\"ERROR: chembl_id does not have a value\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "R983dByAjiZT"
   },
   "source": [
    "Run the SQL query. The ChEMBL downloader will first check to see if you've downloaded the ChEMBL database.  If you haven't, it will download and unpack it for you.  On Google Colab this typically takes 5-10 minutes. Run this cell, then go get a cup of coffee.\n",
    "\n",
    "Once the database is downloaded, it will run the query and return the result as a Pandas dataframe. We also write the results to a csv file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 52,
     "referenced_widgets": [
      "0d7f709341e44e2fa8476b919ed92bb0",
      "33d9280b0831492dadf2d3f7ee9c69ea",
      "3bccef9e9d654155b83f94ce1d836222",
      "dd8762b10e3d481aa9adad6128fb6e0c",
      "b82b6b7924e745abb668f40b00ab851a",
      "3dd7ca0b72c245b2ad76ab5ae26150e4",
      "75130be112734114a1bf0d4d24b2dc89",
      "c71ee70c929d4159acc5e66dc98fea99",
      "ad3a7732eb4448d7bc536a716cd4d7d3",
      "fb1e76c859c247709aa22a198207f41a",
      "b99e90e1ba0e4985a99b0f4823ce6f74"
     ]
    },
    "id": "IG5WXgAUNDEi",
    "outputId": "03a28ce5-10d3-4173-fc7b-c6ad462115e4"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 4.98 s, sys: 2.68 s, total: 7.67 s\n",
      "Wall time: 12.2 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "df = chembl_downloader.query(sql)\n",
    "df.to_csv(f\"{chembl_id}.csv\", sep='\\t', index=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's save the data in case we want to use it later"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "wrote all data too CHEMBL203_all_data.csv\n"
     ]
    }
   ],
   "source": [
    "all_data_output_file = f\"{chembl_id}_all_data.csv\"\n",
    "df.to_csv(all_data_output_file)\n",
    "print(f\"wrote all data too {all_data_output_file}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "mR40g5MZkVQE"
   },
   "source": [
    "Let's look at how many of each of the result types are available in the data we downloaded."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 304
    },
    "id": "KvQ-P_bhOjw4",
    "outputId": "caa8a33c-ec06-4009-b9c4-632f772b5c8e"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "standard_type\n",
       "IC50       13158\n",
       "Kd           809\n",
       "Ki           568\n",
       "EC50         285\n",
       "Potency       35\n",
       "AC50          11\n",
       "Name: count, dtype: int64"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.standard_type.value_counts()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "9-aKnwMhlJd5"
   },
   "source": [
    "As we can see above we have much more IC50 data than any other datatype.  However, as a recent [paper](https://pubs.acs.org/doi/full/10.1021/acs.jcim.4c00049) from Greg Landrum and Sereina Rinker showed, Ki data tends to be more reliable.  Let's download the Ki data.  We will select the three columns critical for building our ML model.\n",
    "- canonical_smiles - the SMILES representation for the chemical structure\n",
    "- molregno - the internal ChEMBL ID for the compounds\n",
    "- pchembl_value - the negative log of the activity\n",
    "\n",
    "If you'd prefer to use a different data type like **Kd** or **IC50**, just change the `standard_type` variable below. \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 424
    },
    "id": "Ink2oFDiSUZ7",
    "outputId": "c6b7d29c-7280-49f0-fe0c-a60e16504a7c"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>canonical_smiles</th>\n",
       "      <th>molregno</th>\n",
       "      <th>pchembl_value</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Brc1cc2c(NCc3ccccc3)ncnc2s1</td>\n",
       "      <td>1839801</td>\n",
       "      <td>6.620</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Brc1cc2c(NCc3ccccn3)ncnc2s1</td>\n",
       "      <td>1839818</td>\n",
       "      <td>5.100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Brc1cc2c(NCc3cccs3)ncnc2s1</td>\n",
       "      <td>1839821</td>\n",
       "      <td>5.860</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Brc1cc2c(NCc3ccncc3)ncnc2s1</td>\n",
       "      <td>1839816</td>\n",
       "      <td>5.410</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Brc1cc2c(Nc3ccccc3)ncnc2s1</td>\n",
       "      <td>1839823</td>\n",
       "      <td>7.100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7751</th>\n",
       "      <td>c1coc(-c2nnc(Cc3nc4ccccc4[nH]3)o2)c1</td>\n",
       "      <td>2201823</td>\n",
       "      <td>4.000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7752</th>\n",
       "      <td>c1csc(-c2cc3nccc(Nc4ccc5[nH]ccc5c4)c3s2)c1</td>\n",
       "      <td>126035</td>\n",
       "      <td>9.000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7753</th>\n",
       "      <td>c1csc(-c2cc3ncnc(Nc4ccc5[nH]ccc5c4)c3s2)c1</td>\n",
       "      <td>125696</td>\n",
       "      <td>8.205</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7754</th>\n",
       "      <td>c1csc(-c2nnc(Cc3nc4ccccc4[nH]3)o2)c1</td>\n",
       "      <td>2215803</td>\n",
       "      <td>4.000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7755</th>\n",
       "      <td>c1nc(Nc2ccc3[nH]ccc3c2)c2sccc2n1</td>\n",
       "      <td>125948</td>\n",
       "      <td>6.220</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>7756 rows × 3 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "                                canonical_smiles  molregno  pchembl_value\n",
       "0                    Brc1cc2c(NCc3ccccc3)ncnc2s1   1839801          6.620\n",
       "1                    Brc1cc2c(NCc3ccccn3)ncnc2s1   1839818          5.100\n",
       "2                     Brc1cc2c(NCc3cccs3)ncnc2s1   1839821          5.860\n",
       "3                    Brc1cc2c(NCc3ccncc3)ncnc2s1   1839816          5.410\n",
       "4                     Brc1cc2c(Nc3ccccc3)ncnc2s1   1839823          7.100\n",
       "...                                          ...       ...            ...\n",
       "7751        c1coc(-c2nnc(Cc3nc4ccccc4[nH]3)o2)c1   2201823          4.000\n",
       "7752  c1csc(-c2cc3nccc(Nc4ccc5[nH]ccc5c4)c3s2)c1    126035          9.000\n",
       "7753  c1csc(-c2cc3ncnc(Nc4ccc5[nH]ccc5c4)c3s2)c1    125696          8.205\n",
       "7754        c1csc(-c2nnc(Cc3nc4ccccc4[nH]3)o2)c1   2215803          4.000\n",
       "7755            c1nc(Nc2ccc3[nH]ccc3c2)c2sccc2n1    125948          6.220\n",
       "\n",
       "[7756 rows x 3 columns]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "standard_type = \"IC50\"\n",
    "output_df = df.query(\"standard_type == @standard_type\")[[\"canonical_smiles\",\"molregno\",\"pchembl_value\"]].groupby([\"canonical_smiles\",\"molregno\"]).mean()\n",
    "output_df = output_df.reset_index()\n",
    "output_df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "I prefer to have the SMILES column called \"SMILES\", let's change that. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>SMILES</th>\n",
       "      <th>molregno</th>\n",
       "      <th>pchembl_value</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Brc1cc2c(NCc3ccccc3)ncnc2s1</td>\n",
       "      <td>1839801</td>\n",
       "      <td>6.620</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Brc1cc2c(NCc3ccccn3)ncnc2s1</td>\n",
       "      <td>1839818</td>\n",
       "      <td>5.100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Brc1cc2c(NCc3cccs3)ncnc2s1</td>\n",
       "      <td>1839821</td>\n",
       "      <td>5.860</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Brc1cc2c(NCc3ccncc3)ncnc2s1</td>\n",
       "      <td>1839816</td>\n",
       "      <td>5.410</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Brc1cc2c(Nc3ccccc3)ncnc2s1</td>\n",
       "      <td>1839823</td>\n",
       "      <td>7.100</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7751</th>\n",
       "      <td>c1coc(-c2nnc(Cc3nc4ccccc4[nH]3)o2)c1</td>\n",
       "      <td>2201823</td>\n",
       "      <td>4.000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7752</th>\n",
       "      <td>c1csc(-c2cc3nccc(Nc4ccc5[nH]ccc5c4)c3s2)c1</td>\n",
       "      <td>126035</td>\n",
       "      <td>9.000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7753</th>\n",
       "      <td>c1csc(-c2cc3ncnc(Nc4ccc5[nH]ccc5c4)c3s2)c1</td>\n",
       "      <td>125696</td>\n",
       "      <td>8.205</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7754</th>\n",
       "      <td>c1csc(-c2nnc(Cc3nc4ccccc4[nH]3)o2)c1</td>\n",
       "      <td>2215803</td>\n",
       "      <td>4.000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7755</th>\n",
       "      <td>c1nc(Nc2ccc3[nH]ccc3c2)c2sccc2n1</td>\n",
       "      <td>125948</td>\n",
       "      <td>6.220</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>7756 rows × 3 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "                                          SMILES  molregno  pchembl_value\n",
       "0                    Brc1cc2c(NCc3ccccc3)ncnc2s1   1839801          6.620\n",
       "1                    Brc1cc2c(NCc3ccccn3)ncnc2s1   1839818          5.100\n",
       "2                     Brc1cc2c(NCc3cccs3)ncnc2s1   1839821          5.860\n",
       "3                    Brc1cc2c(NCc3ccncc3)ncnc2s1   1839816          5.410\n",
       "4                     Brc1cc2c(Nc3ccccc3)ncnc2s1   1839823          7.100\n",
       "...                                          ...       ...            ...\n",
       "7751        c1coc(-c2nnc(Cc3nc4ccccc4[nH]3)o2)c1   2201823          4.000\n",
       "7752  c1csc(-c2cc3nccc(Nc4ccc5[nH]ccc5c4)c3s2)c1    126035          9.000\n",
       "7753  c1csc(-c2cc3ncnc(Nc4ccc5[nH]ccc5c4)c3s2)c1    125696          8.205\n",
       "7754        c1csc(-c2nnc(Cc3nc4ccccc4[nH]3)o2)c1   2215803          4.000\n",
       "7755            c1nc(Nc2ccc3[nH]ccc3c2)c2sccc2n1    125948          6.220\n",
       "\n",
       "[7756 rows x 3 columns]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "output_df.rename(columns={\"canonical_smiles\" : \"SMILES\"},inplace=True)\n",
    "output_df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "QMF4xDY6njfs"
   },
   "source": [
    "Write the data to a csv file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "tp60sXBvYQyt",
    "outputId": "1509bc46-cb8b-4b39-931a-7e5d2886b201"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Saved CHEMBL203_IC50.csv with 7756 rows.\n"
     ]
    }
   ],
   "source": [
    "outfile_name = f\"{chembl_id}_{standard_type}.csv\"\n",
    "output_df.to_csv(outfile_name, index=False)\n",
    "print(f\"Saved {outfile_name} with {len(output_df)} rows.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "CCk62vKcwQQu"
   },
   "source": [
    "Let's take a quick look at the csv file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "nQ7LMbLl0pDB",
    "outputId": "c32f0802-cea6-4dc2-c55a-c664ee91a927"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "SMILES,molregno,pchembl_value\n",
      "Brc1cc2c(NCc3ccccc3)ncnc2s1,1839801,6.62\n",
      "Brc1cc2c(NCc3ccccn3)ncnc2s1,1839818,5.1\n",
      "Brc1cc2c(NCc3cccs3)ncnc2s1,1839821,5.86\n",
      "Brc1cc2c(NCc3ccncc3)ncnc2s1,1839816,5.41\n",
      "Brc1cc2c(Nc3ccccc3)ncnc2s1,1839823,7.1\n",
      "Brc1ccc(C2=NN(c3ccccc3)C(c3ccc4ccccc4c3)C2)cc1,1519273,6.15\n",
      "Brc1ccc(C2=NN(c3ccccc3)C(c3cccc4ccccc34)C2)cc1,1519266,6.31\n",
      "Brc1ccc(C2=NN(c3nc(-c4ccccc4)cs3)C(c3ccc(Br)cc3)C2)cc1,1171953,5.05\n",
      "Brc1ccc(CNc2ccc3ncnc(Nc4cccc(Br)c4)c3c2)cc1,1269681,5.5\n"
     ]
    }
   ],
   "source": [
    "!head {outfile_name}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "lh1mnDNVvrH-"
   },
   "source": [
    "If you're on Google Colab, you can execute the cell below to download the results to your Downloads directory. If you're running the notebook locally the output file will be in the same directory as this notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 17
    },
    "id": "hOQ22LoubEnA",
    "outputId": "2066ba68-3e6c-427a-e223-4a53ea8cfc3c"
   },
   "outputs": [],
   "source": [
    "if IN_COLAB:\n",
    "  files.download(outfile_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "iD2Yi71Culcd"
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.13"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "0d7f709341e44e2fa8476b919ed92bb0": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HBoxModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HBoxModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HBoxView",
      "box_style": "",
      "children": [
       "IPY_MODEL_33d9280b0831492dadf2d3f7ee9c69ea",
       "IPY_MODEL_3bccef9e9d654155b83f94ce1d836222",
       "IPY_MODEL_dd8762b10e3d481aa9adad6128fb6e0c"
      ],
      "layout": "IPY_MODEL_b82b6b7924e745abb668f40b00ab851a"
     }
    },
    "33d9280b0831492dadf2d3f7ee9c69ea": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HTMLModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_3dd7ca0b72c245b2ad76ab5ae26150e4",
      "placeholder": "​",
      "style": "IPY_MODEL_75130be112734114a1bf0d4d24b2dc89",
      "value": "Downloading chembl_35_sqlite.tar.gz: 100%"
     }
    },
    "3bccef9e9d654155b83f94ce1d836222": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "FloatProgressModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "FloatProgressModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "ProgressView",
      "bar_style": "info",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_c71ee70c929d4159acc5e66dc98fea99",
      "max": 1,
      "min": 0,
      "orientation": "horizontal",
      "style": "IPY_MODEL_ad3a7732eb4448d7bc536a716cd4d7d3",
      "value": 1
     }
    },
    "3dd7ca0b72c245b2ad76ab5ae26150e4": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "75130be112734114a1bf0d4d24b2dc89": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "DescriptionStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "ad3a7732eb4448d7bc536a716cd4d7d3": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "ProgressStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "ProgressStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "bar_color": null,
      "description_width": ""
     }
    },
    "b82b6b7924e745abb668f40b00ab851a": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": "hidden",
      "width": null
     }
    },
    "b99e90e1ba0e4985a99b0f4823ce6f74": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "DescriptionStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "c71ee70c929d4159acc5e66dc98fea99": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": "20px"
     }
    },
    "dd8762b10e3d481aa9adad6128fb6e0c": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HTMLModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_fb1e76c859c247709aa22a198207f41a",
      "placeholder": "​",
      "style": "IPY_MODEL_b99e90e1ba0e4985a99b0f4823ce6f74",
      "value": " 4.64G/4.64G [02:29&lt;00:00, 19.9MB/s]"
     }
    },
    "fb1e76c859c247709aa22a198207f41a": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    }
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
